#ifndef DW_GRAFFITI_PROGRAM_INL
#	define DW_GRAFFITI_PROGRAM_INL

namespace dw {
	namespace graffiti {

inline Program::Program()
:	m_id(glCreateProgram())
,	m_attributesHashcode(0)
{
}

inline Program::~Program()
{
	glDeleteProgram(m_id);
}

template< GLenum shaderType >
inline void Program::attach(const Shader< shaderType >& shader)
{
	dwAssert(isValid(), "Invalid call to attach on an invalid program");
	dwAssert(shader.isValid(), "Invalid parameter: shader is not valid");

	glAttachShader(m_id, shader.m_id);
}

inline void Program::activate()
{
	glUseProgram(m_id);
}

inline void Program::deactivate()
{
	glUseProgram(0);
}

inline dw::uint32 Program::getAttributesHashcode() const
{
	return m_attributesHashcode;
}

inline bool Program::hasAttribute(const AttributeDeclaration& attribute) const
{
	dw::uint32 attributeHashcode = attribute::semantic::getHashcode(attribute.semantic, attribute.semanticIndex);

	return (m_attributesHashcode & attributeHashcode) == attributeHashcode;
}

inline bool Program::isValid() const
{
	if (m_id != 0 && glIsProgram(m_id) == GL_TRUE)
	{
		GLint params = 0;

		glGetProgramiv(m_id, GL_DELETE_STATUS, &params);

		return params == GL_FALSE;
	}

	return false;
}

inline bool Program::isLinked() const
{
	if (isValid())
	{
		GLint params = 0;

		glGetProgramiv(m_id, GL_LINK_STATUS, &params);

		return params == GL_TRUE;
	}

	return false;
}

inline const ProgramUniformDeclaration* Program::getUniformDeclaration(const std::string& name) const
{
	UniformsMap::const_iterator foundIt = m_uniforms.find(name);

	return foundIt != m_uniforms.end() ? &(foundIt->second) : NULL;
}

	} // namespace graffiti
} // namespace dw

#endif // !DW_GRAFFITI_PROGRAM_INL
